
/*
 * (a)  (C) 1990 by Adobe Systems Incorporated. All rights reserved.
 *
 * (b)  If this Sample Code is distributed as part of the Display PostScript
 *	System Software Development Kit from Adobe Systems Incorporated,
 *	then this copy is designated as Development Software and its use is
 *	subject to the terms of the License Agreement attached to such Kit.
 *
 * (c)  If this Sample Code is distributed independently, then the following
 *	terms apply:
 *
 * (d)  This file may be freely copied and redistributed as long as:
 *	1) Parts (a), (d), (e) and (f) continue to be included in the file,
 *	2) If the file has been modified in any way, a notice of such
 *      modification is conspicuously indicated.
 *
 * (e)  PostScript, Display PostScript, and Adobe are registered trademarks of
 *	Adobe Systems Incorporated.
 * 
 * (f) THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO
 *	CHANGE WITHOUT NOTICE, AND SHOULD NOT BE CONSTRUED
 *	AS A COMMITMENT BY ADOBE SYSTEMS INCORPORATED.
 *	ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY
 *	OR LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO
 *	WARRANTY OF ANY KIND (EXPRESS, IMPLIED OR STATUTORY)
 *	WITH RESPECT TO THIS INFORMATION, AND EXPRESSLY
 *	DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY, 
 *	FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT
 *	OF THIRD PARTY RIGHTS.
 */

/*
 *	DrawingView.m
 *
 *	This view represents the page that the image is drawn onto. It is
 *	a subview of the DocView. The DocView is the document view of
 *	the ClipView. This view's real size grows with the scale but the
 *	bounds always stays the same.
 *
 *	Version:	2.0
 *	Author:	Ken Fromm
 *	History:
 *			03-07-91		Added this comment.
 */

#import "DrawingView.h"
#import "DrawingViewWraps.h"
#import "DocView.h"
#import "Graphic.h"

#import <appkit/Button.h>
#import <appkit/Control.h>
#import <appkit/Matrix.h>
#import <appkit/SavePanel.h>
#import <appkit/nextstd.h>

#import <objc/List.h>

#import <dpsclient/dpsclient.h>
#import <dpsclient/wraps.h>

extern void initGparms();
extern void setGraphicState();

static const DPSNameEncoding  nameEncoding[4] = {dps_strings, dps_strings,
	dps_indexed, dps_indexed};
static const DPSProgramEncoding  programEncoding[4] = {dps_ascii, dps_ascii,
	dps_binObjSeq, dps_encodedTokens};
static const char  *fileSuffix[4] = {"Asc", "Abbr", "Bos", "Bot"};

@implementation DrawingView

/*
*	Allocate a gstate, set the clipping to NO because it will be clipped
*	by the clip view.
*/
+newFrame:(NXRect *) frm
{	
	self = [super newFrame:frm]; 
	[[self allocateGState] setClipping:NO]; 
	
	drawUpath = [NXApp  getUpathBuffer];

	PSWDefs();

	format = BOS;

	return self;
}

- free
{
	[self  freeGraphics];

	return [super free];
}

- freeGraphics
{
	if (graphicsListId)
		[graphicsListId  freeObjects];
		
	[graphicsListId free];

	return self;
}

- insertList:listId
{
	[self  freeGraphics];
	graphicsListId = listId;

	return self;
}

- setDrawOrigin:(NXPoint *)origin
{
	drawOrigin = *origin;
	
	return self;
}

/*
 *	Saves the file in encapsulated format.  A SavePanel is put up to
 *	ask the user what file name should be used. A suffix is added to
 *	identify the format that has been saved.
 */
- saveFile:sender
{
	id		savepanel, formatmatrix;

	int		count;

	char		tempBuf[MAXPATHLEN+1];

	char		*fileend;

	NXStream	*stream;

	DPSContext	newContext, oldContext;

	savepanel = [SavePanel new];
	formatmatrix = [NXApp  formatMatrix];

	getwd(tempBuf);
	if ([savepanel  runModalForDirectory:tempBuf  file:NULL])
	{
		strcpy(tempBuf, [savepanel filename]);
		fileend = strrchr(tempBuf, '.');
		if (!fileend)
			fileend = &tempBuf[strlen(tempBuf)];

		oldContext = DPSGetCurrentContext();
		count = [formatmatrix  cellCount];
		for (format = 0; format < count; format++)
		{
			if ([[formatmatrix  cellAt:format :0]  state])
			{
				stream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
				if (stream)
				{					
					newContext = DPSCreateStreamContext(stream, 0,
						programEncoding[format], nameEncoding[format], NULL);
					DPSSetContext(newContext);

					[self  printPrologue:tempBuf];
					[self  drawSelf:&bounds  :1];
					[self  printTrailer];

					strcpy(fileend, fileSuffix[format]);
					strcpy(&tempBuf[strlen(tempBuf)], ".eps");
					NXSaveToFile(stream, tempBuf);
					NXCloseMemory(stream, NX_FREEBUFFER);

					DPSSetContext(oldContext);
					if (newContext != oldContext);
						DPSDestroyContext(newContext);
				}
			}
		}
		format = BOS;
	}

	return self;
}

- printPrologue:(char *) filename
{
	time_t		clock;

	char			*printtime;

	DPSContext	ctxt;
	
	ctxt = DPSGetCurrentContext();
	clock = time(0);
	printtime = ctime(&clock);

	DPSPrintf(ctxt, "%%!PS-Adobe-2.0 EPSF-1.2\n");
	DPSPrintf(ctxt, "%%%%Creator: %s\n", [NXApp  appName]);
	DPSPrintf(ctxt, "%%%%CreationDate: %s", printtime);
	DPSPrintf(ctxt, "%%%%Title: %s\n", filename);
	DPSPrintf(ctxt, "%%%%Origin: %f %f\n", bounds.origin.x, bounds.origin.y);
	DPSPrintf(ctxt, "%%%%BoundingBox: %f %f %f %f\n", bounds.origin.x, bounds.origin.y,
		bounds.origin.x + bounds.size.width, bounds.origin.y + bounds.size.height);
	if (format == ABBR)
		DPSPrintf(ctxt, "%%%%DocumentProcSets: Abbreviations 1.0  0\n");
	DPSPrintf(ctxt, "%%%%EndComments\n\n");

	if (format == ABBR)
	{
		DPSPrintf(ctxt, "%%%%BeginProcSet: Abbreviations 1.0 0\n");
		PSWDefs();
		DPSPrintf(ctxt, "%%%%EndProcSet\n");
	}
	else if (format == BOS || format == BOT)
		DPSPrintf(ctxt, "/defineusername {pop pop} bind def\n");

	DPSPrintf(ctxt, "\n%%%%EndProlog\n\n");
	DPSPrintf(ctxt, "realtime\n\n");

	return self;
}

- printTrailer
{
	DPSContext	ctxt;
	
	ctxt = DPSGetCurrentContext();
	DPSPrintf(ctxt, "realtime exch sub == flush\n");
	DPSFlushContext(ctxt);

	return self;
}	

/*
*	Compare the bounds of the object with the rectangle to draw in order to
*	eliminate unnecessary drawing. The modal session stuff is just to
*	intercept the selection of the redraw button in the interface during
*	a trace. (This stops the drawing. It's only check during a trace
*	because the trace can be quite long.)
*/
- drawSelf:(NXRect *)r :(int) count
{
	int			i, num;

	GParms		parms;
	GParms		*p_parms;
	
	NXRect		rect;
	NXRect		*p_rect;

	PSsetgray(NX_WHITE);
	NXRectFill(r);

	initGparms(&parms);
	p_parms = &parms;
	setGraphicState(NULL, &parms, (format == ABBR));
	
	rect = *r;
	rect.origin.x += drawOrigin.x;
	rect.origin.y += drawOrigin.y;
	p_rect = &rect;
	
	PSgsave();
		NXRectClip(r);
		PStranslate(-drawOrigin.x, -drawOrigin.y);
		num = [graphicsListId count];
		for (i = 0; i < num; i++)
			[[graphicsListId  objectAt:i]  drawObject:p_rect  currentParms:p_parms
				withFormat:format];
	PSgrestore();

	return self;			
}

@end
